#ifndef _GUARD_H
#define _GUARD_H

//------------------------------------------

class ScopeGuardImplBase
{
public:
    void Dismiss() const throw()  {dismissed_ = true;}

protected:
    ScopeGuardImplBase() : dismissed_(false) {}
    ScopeGuardImplBase(const ScopeGuardImplBase& other)
    : dismissed_(other.dismissed_)
    {    
		other.Dismiss();    
	}
    
	~ScopeGuardImplBase() 
	{} // nonvirtual (see below why)
    
	mutable bool dismissed_;

private:
    // Disable assignment
    ScopeGuardImplBase& operator=(const ScopeGuardImplBase&);
};

typedef const ScopeGuardImplBase& Guard;

//------------------------------------------

template <typename Fun>
class ScopeGuardImpl : public ScopeGuardImplBase
{
public:
    ScopeGuardImpl(const Fun fun) : fun_(fun) {}

    ~ScopeGuardImpl()
    {
        if (!dismissed_) fun_();
    }

private:
    Fun fun_;
};

//------------------------------------------

template <typename Fun, typename Parm>
class ScopeGuardImplParm : public ScopeGuardImplBase
{
public:
    ScopeGuardImplParm(Fun fun, const Parm& parm) : fun_(fun), parm_(parm) {}

    ~ScopeGuardImplParm()
    {
        if (!dismissed_) fun_(parm_);
    }

private:
    Fun *fun_;
    const Parm parm_;
};

//------------------------------------------

template <typename Fun, typename Parm>
ScopeGuardImplParm<Fun, Parm>
MakeGuardF(Fun& fun, const Parm& parm)
{
    return ScopeGuardImplParm<Fun, Parm>(fun, parm);
}

template <typename Fun>
ScopeGuardImpl<Fun>
MakeGuard(const Fun& fun)
{
	return ScopeGuardImpl<Fun>(fun);
}

//------------------------------------------

template <class Obj, typename MemFun>
class ObjScopeGuardImpl : public ScopeGuardImplBase
{
public:
    ObjScopeGuardImpl(Obj& obj, MemFun memFun)
    : obj_(obj), memFun_(memFun) 
    {}
    ~ObjScopeGuardImpl()
    {
		try
		{
			if (!dismissed_) 
				(obj_.*memFun_)();
		}
		catch(...){}
    }
private:
    Obj& obj_;
    MemFun memFun_;
};

//------------------------------------------

template <class Obj, typename MemFun>
ObjScopeGuardImpl<Obj, MemFun>
MakeGuard(Obj &obj, MemFun fun)
{
	return ObjScopeGuardImpl<Obj, MemFun>(obj, fun);
}

//------------------------------------------

template <class Obj, typename MemFun, typename Param>
class ObjScopeGuardImpl2 : public ScopeGuardImplBase
{
public:
    ObjScopeGuardImpl2(Obj& obj, MemFun memFun, Param parm)
    : obj_(obj), memFun_(memFun), _parm(parm) 
    {}
    ~ObjScopeGuardImpl2()
    {
		try
		{
			if (!dismissed_) 
				(obj_.*memFun_)(_parm);
		}
		catch(...){}
    }
private:
    Obj& obj_;
    MemFun memFun_;
	const Param _parm;
};

//------------------------------------------

template <class Obj, typename MemFun, typename Param>
ObjScopeGuardImpl2<Obj, MemFun, Param>
MakeGuard(Obj &obj, MemFun fun, Param parm)
{
	return ObjScopeGuardImpl2<Obj, MemFun, Param>(obj, fun, parm);
}

//------------------------------------------

#endif // _GUARD_H